import 'dart:math';
import 'package:flutter/material.dart';
import 'package:shining_red_star/definitions/color.dart';
import '../utils/color.dart';

class ShapePainter extends CustomPainter {
  final String shape;
  final Paint thePaint;

  ShapePainter(
    this.shape, {
    Color? color,
  }) : thePaint = Paint()
          ..color = color ?? SchemeColor.seedColor.value
          ..style = PaintingStyle.fill;

  void drawPoint(Canvas canvas, double width, double height) {
    canvas.drawCircle(Offset(width / 2, height / 2), 4, thePaint);
  }

  void drawLine(Canvas canvas, double width, double height) {
    Path path = Path()
      ..moveTo(0, height / 2)
      ..lineTo(width, height / 2);

    canvas.drawPath(
        path,
        thePaint
          ..strokeWidth = 3
          ..style = PaintingStyle.stroke);
  }

  void drawTriangle(Canvas canvas, double width, double height) {
    double sideLength = width;
    double triangleHeight = (sqrt(3) / 2) * sideLength;
    double centerX = width / 2;
    double centerY = height / 2;
    Offset topVertex = Offset(centerX, centerY - triangleHeight / 2);
    Offset bottomLeftVertex =
        Offset(centerX - sideLength / 2, centerY + triangleHeight / 2);
    Offset bottomRightVertex =
        Offset(centerX + sideLength / 2, centerY + triangleHeight / 2);

    Path path = Path()
      ..moveTo(topVertex.dx, topVertex.dy)
      ..lineTo(bottomLeftVertex.dx, bottomLeftVertex.dy)
      ..lineTo(bottomRightVertex.dx, bottomRightVertex.dy)
      ..close();

    canvas.drawPath(path, thePaint);
  }

  void drawSquare(Canvas canvas, double width, double height) {
    canvas.drawRect(Rect.fromLTWH(0, 0, width, height), thePaint);
  }

  void drawRectangle(Canvas canvas, double width, double height) {
    double rectHeight = width * (2 / 3);
    double rectY = (height - rectHeight) / 2;

    canvas.drawRect(Rect.fromLTWH(0, rectY, width, rectHeight), thePaint);
  }

  void drawRhombus(Canvas canvas, double width, double height) {
    double centerX = width / 2;
    double centerY = height / 2;
    Offset top = Offset(centerX, height / 6);
    Offset right = Offset(width, centerY);
    Offset bottom = Offset(centerX, height * 5 / 6);
    Offset left = Offset(0, centerY);

    canvas.drawPath(
      Path()
        ..moveTo(top.dx, top.dy)
        ..lineTo(right.dx, right.dy)
        ..lineTo(bottom.dx, bottom.dy)
        ..lineTo(left.dx, left.dy)
        ..close(),
      thePaint,
    );
  }

  void drawTrapezoid(Canvas canvas, double width, double height) {
    double baseWidth = width;
    double trapezoidHeight = baseWidth * (2 / 3);
    double topBase = baseWidth * (2 / 3);

    double centerX = width / 2;
    double bottomLeftX = centerX - baseWidth / 2;
    double bottomRightX = centerX + baseWidth / 2;
    double topLeftX = centerX - topBase / 2;
    double topRightX = centerX + topBase / 2;
    double centerY = height / 2;
    double topY = centerY - trapezoidHeight / 2;
    double bottomY = centerY + trapezoidHeight / 2;

    canvas.drawPath(
      Path()
        ..moveTo(bottomLeftX, bottomY)
        ..lineTo(topLeftX, topY)
        ..lineTo(topRightX, topY)
        ..lineTo(bottomRightX, bottomY)
        ..close(),
      thePaint,
    );
  }

  void drawPentagon(Canvas canvas, double width, double height) {
    double centerX = width / 2;
    double centerY = height / 2;
    double radius = min(width, height) / 2;
    double innerRatio = 0.382;

    Path path = Path();

    for (int i = 0; i < 5; i++) {
      double angle = (pi * 2 / 5) * i - (pi / 2);
      double x1 = centerX + cos(angle) * radius;
      double y1 = centerY + sin(angle) * radius;
      double x2 = centerX + cos(angle + pi / 5) * radius * innerRatio;
      double y2 = centerY + sin(angle + pi / 5) * radius * innerRatio;

      if (i == 0) {
        path.moveTo(x1, y1);
      } else {
        path.lineTo(x1, y1);
      }

      path.lineTo(x2, y2);
    }

    path.close();
    canvas.drawPath(path, thePaint);
  }

  void drawRound(Canvas canvas, double width, double height) {
    double centerX = width / 2;
    double centerY = height / 2;
    double radius = width / 2;
    canvas.drawCircle(Offset(centerX, centerY), radius, thePaint);
  }

  void drawHalfRound(Canvas canvas, double width, double height) {
    double diameter = min(width, height);
    Offset center = Offset(width / 2, height / 3 * 2);
    double radius = diameter / 2;
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      pi,
      pi,
      true,
      thePaint,
    );
  }

  void drawSector(Canvas canvas, double width, double height) {
    double centerX = width / 2;
    double centerY = height / 2;
    double radius = min(centerX, centerY * 3 / 2);
    Offset center = Offset(centerX, centerY * 3 / 2);
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      -pi * 7 / 8,
      pi * 3 / 4,
      true,
      thePaint,
    );
  }

  void drawOval(Canvas canvas, double width, double height) {
    double longRadius = width / 2;
    double shortRadius = height / (16 / 5);
    double centerX = width / 2;
    double centerY = height / 2;
    canvas.drawOval(
      Rect.fromLTWH(centerX - longRadius, centerY - shortRadius, longRadius * 2,
          shortRadius * 2),
      thePaint,
    );
  }

  void drawHeartShaped(Canvas canvas, double width, double height) {
    double x = width / 2;
    double y = height / 2;
    double a = width / 45;
    List<Offset> vertices = [];
    double times = 360;

    for (int i = 0; i < times; i++) {
      double step = i / times * (pi * 2);
      Offset vector = Offset(
        a * (16 * pow(sin(step), 3)),
        a *
                (13 * cos(step) -
                    5 * cos(2 * step) -
                    2 * cos(3 * step) -
                    cos(4 * step)) +
            2 * a,
      );
      vertices.add(vector);
    }

    canvas.translate(x, y);
    canvas.rotate(pi);
    Path path = Path();
    for (int i = 0; i < times; i++) {
      Offset vector = vertices[i];
      path.lineTo(vector.dx, vector.dy);
    }
    canvas.drawPath(path, thePaint);
  }

  @override
  void paint(Canvas canvas, Size size) {
    switch (shape) {
      case 'point':
        drawPoint(canvas, size.width, size.height);
        break;
      case 'line-segment':
        drawLine(canvas, size.width, size.height);
        break;
      case 'triangle':
        drawTriangle(canvas, size.width, size.height);
        break;
      case 'square':
        drawSquare(canvas, size.width, size.height);
        break;
      case 'rectangle':
        drawRectangle(canvas, size.width, size.height);
        break;
      case 'rhombus':
        drawRhombus(canvas, size.width, size.height);
        break;
      case 'trapezoid':
        drawTrapezoid(canvas, size.width, size.height);
        break;
      case 'pentagon':
        drawPentagon(canvas, size.width, size.height);
        break;
      case 'round':
        drawRound(canvas, size.width, size.height);
        break;
      case 'half-round':
        drawHalfRound(canvas, size.width, size.height);
        break;
      case 'sector':
        drawSector(canvas, size.width, size.height);
        break;
      case 'oval':
        drawOval(canvas, size.width, size.height);
        break;
      case 'heart-shaped':
        drawHeartShaped(canvas, size.width, size.height);
        break;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

class Shape extends StatefulWidget {
  final String shapeId;
  final String? color;

  const Shape({
    super.key,
    required this.shapeId,
    this.color,
  });

  @override
  State<Shape> createState() => _ShapeState();
}

class _ShapeState extends State<Shape> {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      child: AspectRatio(
        aspectRatio: 1,
        child: CustomPaint(
            painter: ShapePainter(
              widget.shapeId,
              color: widget.color != null ? hexToColor(widget.color!) : null,
            )),
      ),
    );
  }
}
